<template>
  <div class="contBody">
    <h2 class="title">Marker标注</h2>
    <div id="marker" class="map__x"></div>
    <div class="btn">
      <div>{{ status }}</div>
      <el-button type="primary" @click="changeStatus('vector')">
        Vector
      </el-button>
      <el-button type="primary" @click="changeStatus('overlay')">
        overlay
      </el-button>
      <el-button type="primary" @click="changeStatus('default')">
        default
      </el-button>
    </div>

    <div id="label" style="display: none">
      <div id="markerLabel" class="markerLabel" title="Marker">
        <a
          class="address"
          id="address"
          target="_blank"
          href="http://www.openlayers.org/"
        >
          标注点
        </a>
      </div>
    </div>
  </div>
</template>

<script>
import { Map, View, Feature, Overlay } from "ol"; // 地图实例方法、视图方法
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import VectorSource from "ol/source/Vector";
import { Style, Stroke, Icon, Fill, Text } from "ol/style";
import { Point } from "ol/geom";
import XYZ from "ol/source/XYZ";
import "ol/ol.css"; // 地图样式

import blueIcon from "@/assets/images/blueIcon.png";

export default {
  name: "MarkerPage",
  data() {
    return {
      map: null,
      status: "default",
    };
  },
  mounted() {
    this.initMap();
  },
  methods: {
    changeStatus(status) {
      this.status = status;
    },
    initMap() {
      //实例化Vector要素，通过矢量图层添加到地图容器中
      const iconFeature = new Feature({
        geometry: new Point([116.28, 39.54]),
        //名称属性
        name: "北京市",
        //大概人口数（万）
        population: 2115,
      });
      const iconStyle = this.createLabelStyle(iconFeature);
      iconFeature.setStyle(iconStyle);

      //矢量标注的数据源
      const vectorSource = new VectorSource({
        features: [iconFeature],
      });

      //矢量标注图层
      const vectorLayer = new VectorLayer({
        source: vectorSource,
        zIndex: 2,
        visible: true,
      });

      // 地图实例
      this.map = new Map({
        target: "marker",
        layers: [
          new TileLayer({
            source: new XYZ({
              url: "http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7", // 新高德地图
            }),
            zIndex: 1,
            visible: true,
          }),
        ],
        view: new View({
          projection: "EPSG:4326",
          center: [120, 39],
          zoom: 6,
        }),
      });

      this.map.addLayer(vectorLayer);

      // 实例化overlay标注，添加到地图容器中
      const marker = new Overlay({
        position: [113.65046, 34.726684],
        positioning: "center-center",
        element: document.getElementById("markerLabel"),
        stopEvent: false,
      });
      this.map.addOverlay(marker);
      marker.getElement().title = "郑州市";
      const text = new Overlay({
        position: [113.65046, 34.726684],
        element: document.getElementById("address"),
      });
      this.map.addOverlay(text);
      text.getElement().innerText = marker.getElement().title;

      //为地图容器添加单击事件监听
      this.map.on("click", (evt) => {
        //鼠标单击点坐标
        var point = evt.coordinate;
        if (this.status == "vector") {
          this.addVectorLabel(point, vectorSource);
        } else if (this.status == "overlay") {
          this.addOverlayLabel(point);
        }
      });
    },
    /**
     * 标注样式
     */
    createLabelStyle(feature) {
      return new Style({
        image: new Icon({
          anchor: [0.5, 60],
          anchorOrigin: "top-right",
          anchorXUnits: "fraction",
          anchorYUnits: "pixels",
          offsetOrigin: "top-right",
          opacity: 1,
          src: blueIcon,
        }),
        text: new Text({
          textAlign: "center",
          textBaseline: "middle",
          font: "normal 14px 微软雅黑",
          text: feature.get("name"),
          fill: new Fill({ color: "#aa3300" }),
          stroke: new Stroke({ color: "#ffcc33", width: 2 }),
        }),
      });
    },

    /**
     * 添加一个新的标注（矢量要素）
     * @param {ol.Coordinate} coordinate 坐标点
     */
    addVectorLabel(coordinate, vectorSource) {
      //实例化Vector要素，通过矢量图层添加到地图容器中
      const newFeature = new Feature({
        // 位置
        geometry: new Point(coordinate),
        //名称属性
        name: "标注点",
      });
      const newStyle = this.createLabelStyle(newFeature);
      newFeature.setStyle(newStyle);

      //将新要素添加到数据源中
      vectorSource.addFeature(newFeature);
    },

    /**
     * 添加一个新的图文标注（overlay标注）
     * @param {ol.Coordinate} coordinate 坐标点
     */
    addOverlayLabel(coordinate) {
      //新增div元素
      let elementDiv = document.createElement("div");
      elementDiv.className = "markerLabel";
      elementDiv.title = "标注点";
      // 获取id为label的元素
      let overlay = document.getElementById("label");
      // 为ID为label的div层添加div子节点
      overlay.appendChild(elementDiv);
      //新增a元素
      let elementA = document.createElement("a");
      elementA.className = "address";
      elementA.href = "#";
      //设置文本
      this.setInnerText(elementA, elementDiv.title);
      // 新建的div元素添加a子节点
      elementDiv.appendChild(elementA);

      //实例化图文标注（图形+文本），添加到地图容器中
      const newMarker = new Overlay({
        position: coordinate,
        positioning: "center-center",
        element: elementDiv,
        stopEvent: false,
      });
      this.map.addOverlay(newMarker);

      const newText = new Overlay({
        position: coordinate,
        element: elementA,
      });
      this.map.addOverlay(newText);
    },

    /**
     * 动态设置元素文本内容（兼容）
     */
    setInnerText(element, text) {
      if (typeof element.textContent == "string") {
        element.textContent = text;
      } else {
        element.innerText = text;
      }
    },
  },
};
</script>

<style lang="css" scoped>
.contBody .title {
  padding: 0 0 24px;
}
.map__x {
  width: 100%;
  height: 600px;
  border: 1px solid #eee;
}

.btn {
  text-align: left;
}
</style>

<style>
.markerLabel {
  width: 20px;
  height: 20px;
  border: 1px solid #088;
  border-radius: 10px;
  background-color: #0ff;
  opacity: 1;
}

.address {
  text-decoration: none;
  color: #aa3300;
  font-size: 14px;
  font-weight: bold;
  text-shadow: black 0.1em 0.1em 0.2em;
}
</style>
